package Reflect

import (
	"fmt"
	"reflect"
)

func GetField(obj interface{}, name string) (i interface{}, err error) {
	// 获取obj的反射对象
	objValue := reflect.ValueOf(obj)
	if objValue.Kind() == reflect.Ptr {
		// 如果是指针，则解引用
		objValue = objValue.Elem()
	}

	// 获取字段的反射对象
	fieldValue := objValue.FieldByName(name)
	if !fieldValue.IsValid() {
		return nil, fmt.Errorf("field %s is not valid", name)
	}

	v := fieldValue.Interface()
	return v, nil
}

// SetField 使用反射设置结构体字段的值，obj必须是个指针类型
func SetField(obj interface{}, name string, value interface{}) error {
	// 获取obj的反射对象
	objValue := reflect.ValueOf(obj)
	if objValue.Kind() == reflect.Ptr {
		// 如果是指针，则解引用
		objValue = objValue.Elem()
	}

	// 获取字段的反射对象
	fieldValue := objValue.FieldByName(name)
	if !fieldValue.IsValid() {
		return fmt.Errorf("field %s is not valid", name)
	}

	// 判断字段是否可以设置
	if !fieldValue.CanSet() {
		return fmt.Errorf("field %s is not settable", name)
	}

	// 将value的反射对象设置给obj的字段
	valValue := reflect.ValueOf(value)
	if fieldValue.Type() != valValue.Type() {
		return fmt.Errorf("provided value is of type %s, should be of type %s", valValue.Type(), fieldValue.Type())
	}
	fieldValue.Set(valValue)

	return nil
}

// MakeValueType 将ptr类型的Type转换为val类型的Type
func MakeValueType(ptr reflect.Type) reflect.Type {
	// 如果是指针，则解引用
	if ptr.Kind() == reflect.Ptr {
		return ptr.Elem()
	}
	return ptr
}
